home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 2.iso
/
STUTTGART
/
TEMP
/
GNU
/
flex
/
C
< prev
next >
Wrap
Text File
|
1995-06-28
|
8KB
|
254 lines
C++
Previous: <Performance=>Performanc> * Next: <Incompatibilities=>Incompatib> * Up: <Top=>!Root>
#Wrap on
{fH3}Generating C++ scanners{f}
{fCode}flex{f} provides two different ways to generate scanners for
use with C++. The first way is to simply compile a
scanner generated by {fCode}flex{f} using a C++ compiler instead of a C
compiler. You should not encounter any compilations
errors (please report any you find to the email address
given in the Author section below). You can then use C++
code in your rule actions instead of C code. Note that
the default input source for your scanner remains {fCode}yyin{f},
and default echoing is still done to {fCode}yyout{f}. Both of these
remain {fEmphasis}FILE \*{f} variables and not C++ {fCode}streams{f}.
You can also use {fCode}flex{f} to generate a C++ scanner class, using
the {fEmphasis}-+{f} option, (or, equivalently, {fEmphasis}%option c++{f}), which
is automatically specified if the name of the flex executable ends
in a {fEmphasis}+{f}, such as {fCode}flex++{f}. When using this option, flex
defaults to generating the scanner to the file {fCite}lex.yy.cc{f} instead
of {fCite}lex.yy.c{f}. The generated scanner includes the header file
{fCite}FlexLexer.h{f}, which defines the interface to two C++ classes.
The first class, {fCode}FlexLexer{f}, provides an abstract base
class defining the general scanner class interface. It
provides the following member functions:
#Indent +4
#Indent
{fEmphasis}const char\* YYText(){f}
#Indent +4
returns the text of the most recently matched
token, the equivalent of {fCode}yytext{f}.
#Indent
{fEmphasis}int YYLeng(){f}
#Indent +4
returns the length of the most recently matched
token, the equivalent of {fCode}yyleng{f}.
#Indent
{fEmphasis}int lineno() const{f}
#Indent +4
returns the current input line number (see {fEmphasis}%option yylineno{f}),
or 1 if {fEmphasis}%option yylineno{f} was not used.
#Indent
{fEmphasis}void set\_debug( int flag ){f}
#Indent +4
sets the debugging flag for the scanner, equivalent to assigning to
{fCode}yy\_flex\_debug{f} (see the Options section above). Note that you
must build the scanner using {fEmphasis}%option debug{f} to include debugging
information in it.
#Indent
{fEmphasis}int debug() const{f}
#Indent +4
returns the current setting of the debugging flag.
#Indent
Also provided are member functions equivalent to
{fEmphasis}yy\_switch\_to\_buffer(), yy\_create\_buffer(){f} (though the
first argument is an {fEmphasis}istream\*{f} object pointer and not a
{fEmphasis}FILE\*{f}, {fEmphasis}yy\_flush\_buffer(){f}, {fEmphasis}yy\_delete\_buffer(){f},
and {fEmphasis}yyrestart(){f} (again, the first argument is a {fEmphasis}istream\*{f}
object pointer).
The second class defined in {fCite}FlexLexer.h{f} is {fCode}yyFlexLexer{f},
which is derived from {fCode}FlexLexer{f}. It defines the following
additional member functions:
#Indent +4
#Indent
{fEmphasis}yyFlexLexer( istream\* arg\_yyin = 0, ostream\* arg\_yyout = 0 ){f}
#Indent +4
constructs a {fCode}yyFlexLexer{f} object using the given
streams for input and output. If not specified,
the streams default to {fCode}cin{f} and {fCode}cout{f}, respectively.
#Indent
{fEmphasis}virtual int yylex(){f}
#Indent +4
performs the same role is {fEmphasis}yylex(){f} does for ordinary
flex scanners: it scans the input stream, consuming
tokens, until a rule's action returns a value. If you derive a subclass
{fStrong}S{f}
from {fCode}yyFlexLexer{f}
and want to access the member functions and variables of
{fStrong}S{f}
inside {fEmphasis}yylex(){f},
then you need to use {fEmphasis}%option yyclass="{fStrong}S{f}"{f}
to inform {fCode}flex{f}
that you will be using that subclass instead of {fCode}yyFlexLexer{f}.
In this case, rather than generating {fEmphasis}yyFlexLexer::yylex(){f},
{fCode}flex{f} generates {fEmphasis}{fStrong}S{f}::yylex(){f}
(and also generates a dummy {fEmphasis}yyFlexLexer::yylex(){f}
that calls {fEmphasis}yyFlexLexer::LexerError(){f}
if called).
#Indent
{fEmphasis}virtual void switch\_streams(istream\* new\_in = 0, ostream\* new\_out = 0){f}
#Indent +4
reassigns {fCode}yyin{f} to {fCode}new\_in{f}
(if non-nil)
and {fCode}yyout{f} to {fCode}new\_out{f}
(ditto), deleting the previous input buffer if {fCode}yyin{f}
is reassigned.
#Indent
{fEmphasis}int yylex( istream\* new\_in = 0, ostream\* new\_out = 0 ){f}
#Indent +4
first switches the input streams via {fEmphasis}switch\_streams( new\_in, new\_out ){f}
and then returns the value of {fEmphasis}yylex(){f}.
#Indent
In addition, {fCode}yyFlexLexer{f} defines the following protected
virtual functions which you can redefine in derived
classes to tailor the scanner:
#Indent +4
#Indent
{fEmphasis}virtual int LexerInput( char\* buf, int max\_size ){f}
#Indent +4
reads up to {fEmphasis}max\_size{f} characters into {fStrong}buf{f} and
returns the number of characters read. To indicate
end-of-input, return 0 characters. Note that
"interactive" scanners (see the {fEmphasis}-B{f} and {fEmphasis}-I{f} flags)
define the macro {fCode}YY\_INTERACTIVE{f}. If you redefine
{fCode}LexerInput(){f} and need to take different actions
depending on whether or not the scanner might be
scanning an interactive input source, you can test
for the presence of this name via {fEmphasis}\#ifdef{f}.
#Indent
{fEmphasis}virtual void LexerOutput( const char\* buf, int size ){f}
#Indent +4
writes out {fStrong}size{f} characters from the buffer {fStrong}buf{f},
which, while NUL-terminated, may also contain
"internal" NUL's if the scanner's rules can match
text with NUL's in them.
#Indent
{fEmphasis}virtual void LexerError( const char\* msg ){f}
#Indent +4
reports a fatal error message. The default version
of this function writes the message to the stream
{fCode}cerr{f} and exits.
#Indent
Note that a {fCode}yyFlexLexer{f} object contains its {fEmphasis}entire{f}
scanning state. Thus you can use such objects to create
reentrant scanners. You can instantiate multiple instances of
the same {fCode}yyFlexLexer{f} class, and you can also combine
multiple C++ scanner classes together in the same program
using the {fEmphasis}-P{f} option discussed above.
Finally, note that the {fEmphasis}%array{f} feature is not available to
C++ scanner classes; you must use {fEmphasis}%pointer{f} (the default).
Here is an example of a simple C++ scanner:
#Wrap off
#fCode
\/\/ An example of using the flex C++ scanner class.
%\{
int mylineno = 0;
%\}
string \\"[^\\n"]+\\"
ws [ \\t]+
alpha [A-Za-z]
dig [0-9]
name (\{alpha\}|\{dig\}|\\$)(\{alpha\}|\{dig\}|[\_.\\-\/$])\*
num1 [-+]?\{dig\}+\\.?([eE][-+]?\{dig\}+)?
num2 [-+]?\{dig\}\*\\.\{dig\}+([eE][-+]?\{dig\}+)?
number \{num1\}|\{num2\}
%%
\{ws\} \/\* skip blanks and tabs \*\/
"\/\*" \{
int c;
while((c = yyinput()) != 0)
\{
if(c == '\\n')
++mylineno;
else if(c == '\*')
\{
if((c = yyinput()) == '\/')
break;
else
unput(c);
\}
\}
\}
\{number\} cout << "number " << YYText() << '\\n';
\\n mylineno++;
\{name\} cout << "name " << YYText() << '\\n';
\{string\} cout << "string " << YYText() << '\\n';
%%
Version 2.5 December 1994 44
int main( int \/\* argc \*\/, char\*\* \/\* argv \*\/ )
\{
FlexLexer\* lexer = new yyFlexLexer;
while(lexer->yylex() != 0)
;
return 0;
\}
#f
#Wrap on
If you want to create multiple (different) lexer classes,
you use the {fEmphasis}-P{f} flag (or the {fEmphasis}prefix={f} option) to rename each
{fCode}yyFlexLexer{f} to some other {fCode}xxFlexLexer{f}. You then can
include {fEmphasis}<FlexLexer.h>{f} in your other sources once per lexer
class, first renaming {fCode}yyFlexLexer{f} as follows:
#Wrap off
#fCode
\#undef yyFlexLexer
\#define yyFlexLexer xxFlexLexer
\#include <FlexLexer.h>
\#undef yyFlexLexer
\#define yyFlexLexer zzFlexLexer
\#include <FlexLexer.h>
#f
#Wrap on
if, for example, you used {fEmphasis}%option prefix="xx"{f} for one of
your scanners and {fEmphasis}%option prefix="zz"{f} for the other.
IMPORTANT: the present form of the scanning class is
{fEmphasis}experimental{f} and may change considerably between major
releases.